package com.wondersgroup.fjzlpt.gateway.filtes;

import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.wondersgroup.fjzlpt.gateway.feign.CertService;
import com.wondersgroup.fjzlpt.gateway.filtes.exception.QuickZuulFilterException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 客户端认证过滤器
 * 验证登录
 * @author lion
 *
 */
public class QuickCertClientFilter extends ZuulFilter{

	protected final Log logger = LogFactory.getLog(getClass());

	/** 过滤器忽略列表 */
	private List<String> ignoreParrent = Collections.emptyList();
	/**需要验证的列表*/
	private List<String> certParrent = Collections.emptyList();
	/** 认证域的key */
	private String domainKey;
	/**登录页面*/
	private String loginUrl;
	/**ant匹配方式*/
	AntPathMatcher antPathMatcher = new AntPathMatcher();
	@Autowired
	CertService certService;

	public QuickCertClientFilter(String domainKey, String loginUrl, List ignoreParrent, List certParrent){
		this.domainKey = domainKey;
		this.loginUrl = loginUrl;
		this.ignoreParrent = ignoreParrent;
		this.certParrent = certParrent;
	}

	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

	@Override
	public int filterOrder() {
		return FilterConstants.PRE_DECORATION_FILTER_ORDER-2;
	}

	/**
	 * 默认为false
	 * 优先匹配忽略列表
	 * @return
	 */
	@Override
	public boolean shouldFilter() {
		boolean should = false;
		RequestContext ctx = RequestContext.getCurrentContext();
		String uri = ctx.getRequest().getRequestURI();
		if(!matchParrent(this.ignoreParrent, uri)){
			should = matchParrent(this.certParrent, uri);
		}
		logger.debug(uri + ": should="+should);
		return should;
	}

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		String domainId = getCookieValue(domainKey, request);
		if (StringUtils.isEmpty(domainId)) {
			// 跳转登录
			redirectLogin(ctx, false);
		} else {
			JSONObject certInfo = null;
			JSONObject json = new JSONObject(2);
			json.put("domainKey", domainKey);
			json.put("domainId", domainId);
			try {
				certInfo = this.certService.doCert(json);
			}catch (Exception e) {
				e.printStackTrace();
				throw new QuickZuulFilterException(QuickZuulFilterException.TYPE_CERT_FAIL, e.getMessage());
			}
			if(!certInfo.getBoolean("state")) {
				redirectLogin(ctx, true);
			}else{
				ctx.set ("certInfo", certInfo);
			}
		}
		return null;
	}

	private String getCookieValue(String cookieName, HttpServletRequest request) {
		String value = "";
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				cookie.setMaxAge(0);
				String name = cookie.getName();
				if (cookieName.equals(name)) {
					value = cookie.getValue();
					break;
				}
			}
		}
		return value;
	}

	private void redirectLogin(RequestContext ctx, boolean isTimeout) {
		/*改成直接抛出认证超时异常*/
		if(isTimeout){
			throw new QuickZuulFilterException(QuickZuulFilterException.TYPE_CERT_TIME_OUT, "认证超时");
		}else{
			/*设置不需要进入网关内部的项目*/
			ctx.setSendZuulResponse(false);
			try {
				ctx.getResponse().sendRedirect(this.loginUrl);
			} catch (IOException e) {
				e.printStackTrace();
				throw new QuickZuulFilterException(QuickZuulFilterException.TYPE_ERROR_LOGIN, "跳转登录出现异常");
			}
		}
	}

	/**
	 * 匹配URI
	 * @param parrent
	 * @param uri
	 * @return
	 */
	private boolean matchParrent(List parrent, String uri){
		boolean isMatch = false;
		if(parrent!= null && parrent.size()>0){
			Iterator<String> iter = parrent.iterator();
			while(iter.hasNext()){
				String p = iter.next();
				isMatch = this.antPathMatcher.match(p, uri);
				if(isMatch){
					break;
				}
			}
		}
		return isMatch;
	}
}
